﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Data.Linq;
using Zeus.DAL.LINQ.Extension;

namespace Zeus.DAL.LINQ
{
    public sealed class LinqRepository<T> : IRepository<T> where T : class
    {


        private DataContext _context;

        public LinqRepository(DataContext context)
        {
            // Note: DataContext属于linq的方法，内聚性比较强。可以采用unitOfWork方法对DataContext解耦。

            //if (unitOfWork == null)
            //    throw new ArgumentNullException("unitOfWork is NULL");
            //_context = unitOfWork as DataContext;
            _context = context;
            _context.Log = new DebuggerWriter();
        }

        #region IRepository<T> 成员

        public T GetById(object id)
        {
            var itemParameter = Expression.Parameter(typeof(T), "item");
            var whereExpression = Expression.Lambda<Func<T, bool>>
                (
                Expression.Equal(
                    Expression.Property(
                        itemParameter,
                        typeof(T).GetPrimaryKey().Name
                        ),
                    Expression.Constant(id)
                    ),
                new[] { itemParameter }
                );

            return GetAll().Where(whereExpression).SingleOrDefault();
        }

        public TEntity GetById<TEntity>(object id) where TEntity : class
        {
            var itemParameter = Expression.Parameter(typeof(TEntity), "item");

            var whereExpression = Expression.Lambda<Func<TEntity, bool>>
                (
                Expression.Equal(
                    Expression.Property(
                        itemParameter,
                        typeof(TEntity).GetPrimaryKey().Name
                        ),
                    Expression.Constant(id)
                    ),
                new[] { itemParameter }
                );

            return GetAll<TEntity>().Where(whereExpression).SingleOrDefault();
        }


        public T Get(Expression<Func<T, bool>> predicate)
        {
            return GetAll().Where(predicate).FirstOrDefault();
        }
        public TEntity Get<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class
        {
            return GetAll<TEntity>().Where(predicate).FirstOrDefault();
        }

        public IQueryable<T> GetAll()
        {
            return _context.GetTable<T>();
        }

        public IQueryable<TEntity> GetAll<TEntity>() where TEntity : class
        {
            return _context.GetTable<TEntity>();
        }

        [Obsolete]
        public IEnumerable<T> GetAll(Func<T, bool> exp)
        {
            return _context.GetTable<T>().Where(exp);
        }

        public bool IsExists(Expression<Func<T, bool>> predicate)
        {
            int cnt = GetAll().Where(predicate).Count();
            if (cnt > 0)
                return true;

            return false;
        }

        public void Add(T entity)
        {
            _context.GetTable<T>().InsertOnSubmit(entity);
        }

        public void Add<TEntity>(TEntity entity) where TEntity : class
        {
            _context.GetTable<TEntity>().InsertOnSubmit(entity);
        }

        /// <summary>
        ///  批量Insert
        /// </summary>
        /// <param name="entitys"></param>
        public void AddBatch(List<T> entitys)
        {
            _context.GetTable<T>().InsertAllOnSubmit(entitys);
        }
        public void AddBatch<TEntity>(List<TEntity> entitys) where TEntity : class
        {
            _context.GetTable<TEntity>().InsertAllOnSubmit(entitys);
        }


        #region Extensions

        public void Delete(object id)
        {
            _context.GetTable<T>().DeleteByPK(id);
            //_context.SubmitChanges();
        }

        public void DeleteBy<TEntity>(TEntity entity) where TEntity : class
        {
            _context.GetTable<TEntity>().DeleteOnSubmit(entity);
            //_context.SubmitChanges();
        }
        public void DeleteBatch<TEntity>(IQueryable<TEntity> predicate) where TEntity : class
        {
            _context.GetTable<TEntity>().DeleteBatch(predicate);
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="updater"></param>
        public void UpdateBatch(IQueryable<T> predicate, Expression<Func<T, T>> updater)
        {
            _context.GetTable<T>().UpdateBatch(predicate, updater);
        }
        public void UpdateBatch<TEntity>(IQueryable<TEntity> predicate, Expression<Func<TEntity, TEntity>> updater) where TEntity : class
        {
            _context.GetTable<TEntity>().UpdateBatch(predicate, updater);
        }
        /// <summary>
        ///  批量删除
        /// </summary>
        /// <param name="predicate"></param>
        public void DeleteBatch(IQueryable<T> predicate)
        {
            _context.GetTable<T>().DeleteBatch(predicate);
        }

        #endregion


        public void SubmitChanges()
        {
            _context.SubmitChanges();
        }


        public int ExcuteCommand(string command, params object[] args)
        {
            return _context.ExecuteCommand(command, args);
        }

        public DateTime GetSysDate()
        {
            return _context.ExecuteQuery<DateTime>("select getdate()").SingleOrDefault();
        }

        public IEnumerable<T> ExecuteQuery(string command, params object[] args)
        {
            return _context.ExecuteQuery<T>(command, args);
        }

        public IEnumerable<TEntity> ExecuteQuery<TEntity>(string command, params Object[] args)
        {
            return _context.ExecuteQuery<TEntity>(command, args);
        }
        #endregion

    }
}